/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/19 23:53
  *
  * @file       pd_dma.c
  * @brief      DMA peripheral driver.
  *
  * @note       This file contains the peripheral driver for the DMA.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date          Author       Notes
  *   2024/6/19     Chris        the first version
  *
  ******************************************************************************
  */


#include <stm32f4xx_ll_bus.h>
#include <stm32f4xx_ll_dma.h>
#include "pd_dma.h"

static void DMA_init_(const DMA *this) {
    if      (this->DMAx == DMA1) LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
    else if (this->DMAx == DMA2) LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);

    // DMA init
    LL_DMA_InitTypeDef DMA_InitStruct = {0};
    LL_DMA_StructInit(&DMA_InitStruct);
    DMA_InitStruct.PeriphOrM2MSrcAddress  = this->PeriphOrM2MSrcAddress;    // DMA_SxPAR  [31:0]
    DMA_InitStruct.MemoryOrM2MDstAddress  = this->MemoryOrM2MDstAddress;    // DMA_SxM0AR [31:0]
    DMA_InitStruct.Direction              = this->Direction;                // DMA_SxCR   [7:6]
    DMA_InitStruct.Mode                   = this->Mode;                     // DMA_SxCR   [8:8]
    DMA_InitStruct.PeriphOrM2MSrcIncMode  = this->PeriphOrM2MSrcIncMode;    // DMA_SxCR   [9:9]
    DMA_InitStruct.MemoryOrM2MDstIncMode  = this->MemoryOrM2MDstIncMode;    // DMA_SxCR   [10:10]
    DMA_InitStruct.PeriphOrM2MSrcDataSize = this->PeriphOrM2MSrcDataSize;   // DMA_SxCR   [12:11]
    DMA_InitStruct.MemoryOrM2MDstDataSize = this->MemoryOrM2MDstDataSize;   // DMA_SxCR   [14:13]
    DMA_InitStruct.NbData                 = this->NbData;                   // DMA_SxNDTR [15:0]
    DMA_InitStruct.Channel                = this->Channel;                  // DMA_SxCR   [27:25]
    DMA_InitStruct.Priority               = this->Priority;                 // DMA_SxCR   [5:5]

    DMA_InitStruct.FIFOMode               = this->FIFOMode;
    DMA_InitStruct.FIFOThreshold          = this->FIFOThreshold;
    DMA_InitStruct.MemBurst               = this->MemBurst;
    DMA_InitStruct.PeriphBurst            = this->PeriphBurst;

    LL_DMA_Init(this->DMAx, this->Stream, &DMA_InitStruct);

    LL_DMA_EnableStream(this->DMAx, this->Stream);
}

void DMA_constructor(DMA *this, DMA_TypeDef *DMAx, uint32_t PeriphOrM2MSrcAddress, uint32_t MemoryOrM2MDstAddress,
                     uint32_t NbData, uint32_t Channel, uint32_t Stream) {
    static struct DMAVtbl vtbl = {
        .init = &DMA_init_,
    };

    this->vptr = &vtbl;
    this->DMAx = DMAx;
    this->PeriphOrM2MSrcAddress = PeriphOrM2MSrcAddress;
    this->MemoryOrM2MDstAddress = MemoryOrM2MDstAddress;

    this->Direction              = LL_DMA_DIRECTION_MEMORY_TO_MEMORY;
    this->Mode                   = LL_DMA_MODE_NORMAL;
    this->PeriphOrM2MSrcIncMode  = LL_DMA_PERIPH_INCREMENT;
    this->MemoryOrM2MDstIncMode  = LL_DMA_MEMORY_INCREMENT;
    this->PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE;
    this->MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
    this->NbData                 = NbData;
    this->Channel                = Channel;
    this->Priority               = LL_DMA_PRIORITY_MEDIUM;

    this->FIFOMode               = LL_DMA_FIFOMODE_DISABLE;
    this->FIFOThreshold          = LL_DMA_FIFOTHRESHOLD_1_4;
    this->MemBurst               = LL_DMA_MBURST_SINGLE;
    this->PeriphBurst            = LL_DMA_PBURST_SINGLE;

    this->Stream                 = Stream;
}
